配合分支:day26/start,Repo: 按我
剩幾天就要結束了,趕緊把日記匯出來,怕真的動了真感情!這次就來做一個 class 方便把目前所有的日記做輸出吧。先不要把事情弄的太複雜,先轉成文字就好。
只需要將存在裝置儲存空間裡頭的資訊讀取出來後,取得日記的 Entity,就能夠用這些資訊組成這次需要的輸出資料。

這個與存的日記有關係的 Class,從資料流的經驗來看,應該要放在 ViewModel 處理。一般來說,ViewModel 會作為「資料」和「畫面」的糨糊層,透過它溝通兩者。
這樣說起來,就需要將 DiaryExporter 注入到 ViewModel 之中,即要調整 PhotoDiaryViewModel 的建構子,和建構他的 Factory Class(ViewModel 是 Google 提供的 Library,需要用它提供的方法來建造)。
class PhotoDiaryViewModel(
application: Application,
private val diaryStore: DiaryStore,
private val diaryExporter: DiaryExporter // 👈🏼 加入
)
接下來調整工廠:

目前工廠在 MainActivity 生成,那邊也需要更新。
private val photoDiaryViewModel: PhotoDiaryViewModel by viewModels {
val diaryStore = LocalDiaryStorage(applicationContext)
// 👇🏼 多了這塊
val diaryExporter = DiaryExporter(diaryStore)
PhotoDiaryViewModelFactory(diaryStore, diaryExporter)
}
因為這專案也寫了測試,這邊也需要 inject 東西進去。請各位自行調整成:
val viewModel = PhotoDiaryViewModel(application(), diaryStore, DiaryExporter(diaryStore))
呼,改了個建構子沒想到要調整個地方這麼多!
預計要做的事情就是顯示在一個 Dialog 上面就好(我們時間真的不多 =. =),故只需要提供「顯示在 Dialog 上的 output 就行了。」很簡單,很粗暴。
// 👇🏼 多一個 getter
var previewText by mutableStateOf<String?>(null)
private set
提供這些方法即可:
fun previewSavedDiaries() {
previewText = diaryExporter.export()
}
fun closePreview() {
previewText = null
}

上面越來越擠啦!這次目標是加入一個「預覽已儲存日記」的按鈕。點擊之後一個 Dialog 跳出來,它會跟 previewText 取得現在日記的預覽。在列表上面加入按鈕,也就是調整 DiaryList。

當按鈕點擊後,去請 ViewModel 叫 exporter 開始上班。
onPreviewClick = { viewModel.previewSavedDiaries() }
接下來準備對話框,用 Android Jetpack Compose 內建的 AlertDialog 即可。

要怎麼樣才會顯示這個對話框呢?只要 previewText 不是空的就可以顯示。
加在最上面的 PhotoDiaryApp 區塊內:
val previewText = viewModel.previewText
if (previewText != null) {
DiaryPreviewDialog(
previewText = previewText,
// 👇🏼 按下 Close 或是把對話框 dismiss 掉,就清空 previewText
onClose = { viewModel.closePreview() }
)
}

P.S:完整的 Repo 裡頭的程式碼也加上了測試,有興趣的讀者歡迎開啟 GitHub 查看。
配合分支:day26/plain-text-preview,Repo: 按我
想要 Markdown ⋯ 對吧?你的眼神已經出賣你了。就來強化這個部分,預計加入一個下拉選單選擇格式:純文字、Markdown。這邊做法都是老調重彈,掌握了 25 天進度,絕對難不倒你!
先加入 enum class:
enum class DiaryExportFormat(
val displayName: String
) {
PLAIN_TEXT("純文字"),
MARKDOWN("Markdown")
}
有了這個之後,DiaryExporter 就可以對不同的格式做相對應的處理。

這邊操作和「修改心情」一樣,也需要在 ViewModel 提供狀態供使用者紀錄。
// getter
var selectedExportFormat by mutableStateOf(DiaryExportFormat.PLAIN_TEXT) // 👀 預設純文字
private set
// setter
fun updateExportFormat(format: DiaryExportFormat) {
selectedExportFormat = format
}
// 要求 previewText 更新時,要傳入 Format
fun previewSavedDiaries() {
previewText = diaryExporter.export(selectedExportFormat)
}
接著, 在 DiaryList 再加入一個下拉式選單:

在 DiaryList 更新,最終接上 PhotoDiaryApp 這一段 Flow 就請讀者自行完成囉!
完成會像這個樣子:
